from pychartdir import *
from service import *
from time import strftime, gmtime
import base
import blue
import draw
import login
import os
import service
import sys
import trinity
import uix
import uthread
import util
import xtriui
import shutil
import uiutil
import log
import uicls
import uiconst
setLicenseCode('DIST-0000-05de-f7ec-ffbeURDT-232Q-M544-C2XM-BD6E-C452')
DEBUGMODE = False
MAX_ICON_RANGE = 200

def Msg(msg):
    eve.Message('CustomNotify', {'notify': msg})
    log.general.Log(msg, log.LGNOTICE)
    print msg



class WebTools(Service):
    __guid__ = 'svc.webtools'
    __exportedcalls__ = {'SetVars': [],
     'GetVars': [],
     'GoSlimLogin': [],
     'IconsRender': [],
     'NothingRender': []}
    __notifyevents__ = ['OnClientReady']

    def __init__(self):
        Service.__init__(self)
        self.Reset()



    def Run(self, memStream = None):
        Service.Run(self, memStream)



    def Stop(self, stream):
        Service.Stop(self)



    def Reset(self):
        self.renderVars = []
        self.events = {}



    def OnClientReady(self, what):
        self.events[what] = True



    def WaitForEvent(self, event):
        while ((event not in self.events) or (not self.events[event])):
            blue.pyos.synchro.Yield()

        self.events[event] = False



    def TypesRender(self):
        self.DoRenderTypes(32)
        self.DoRenderTypes(64)



    def DoRenderTypes(self, sz):
        folderLabel = 'Types'
        filePath = (blue.win32.SHGetFolderPath(blue.win32.CSIDL_PERSONAL) + ('/EVE/capture/Screenshots/%s/' % folderLabel))
        dr = DirectoryRoutines()
        dr.GenericCheckCreateDirectory(filePath)
        CSAA_FMT = trinity.TRIMULTISAMPLE_8_SAMPLES
        CSAA_FMT = trinity.TRIMULTISAMPLE_NONE
        CSAA_QTY = 2
        CSAA_QTY = 0
        baseTexture = trinity.TriSurfaceManaged(trinity.device.CreateRenderTarget, sz, sz, trinity.TRIFMT_A8R8G8B8, CSAA_FMT, CSAA_QTY, 0)
        stencil = trinity.TriSurfaceManaged(trinity.device.CreateDepthStencilSurface, sz, sz, trinity.TRIFMT_D24S8, CSAA_FMT, CSAA_QTY, False)
        ui = trinity.TriUI()
        ui.CreateUILib()
        ui.display = True
        ui.desktopBottom = ui.deviceBottom = sz
        ui.desktopLeft = ui.deviceLeft = 0
        ui.desktopRight = ui.deviceRight = sz
        ui.desktopTop = ui.deviceTop = 0
        toRender = []
        godma = sm.GetService('godma')
        for t in cfg.invtypes:
            if (t.graphicID or t.iconID):
                toRender.append(t.typeID)

        toRender.sort()
        photoSvc = sm.GetService('photo')
        print ('Rendering out %s types' % len(toRender))
        numSkipped = 0
        for (counter, typeID,) in enumerate(toRender):
            name = (filePath + ('%s_%s.png' % (typeID, sz)))
            if os.path.isfile(name):
                numSkipped += 1
                continue
            sys.stdout.write('.')
            icon = uicls.Icon(parent=ui, pos=(0,
             0,
             sz,
             sz), ignoreSize=True, state=uiconst.UI_DISABLED)
            techIcon = uicls.Icon(parent=ui, pos=(0, 0, 16, 16), align=uiconst.TOPLEFT, state=uiconst.UI_NORMAL)
            icon.ChangeIcon(typeID=typeID, size=sz, ignoreSize=True)
            uix.GetTechLevelIcon(techIcon, 1, typeID)
            renderJob = trinity.CreateRenderJob('ui')
            renderJob.SetRenderTarget(baseTexture)
            renderJob.SetDepthStencil(stencil)
            cl = renderJob.Clear((0.0, 0.0, 0.0, 0.0), 1.0)
            cl.isDepthCleared = False
            blue.resMan.Wait()
            i = 0
            while photoSvc.byTypeID_IsRunning:
                if (i > 20):
                    print ('waited for photoservice for a long time... %s' % i)
                blue.pyos.synchro.Sleep(50)
                i += 1

            uiutil.Flush(ui.uilib.desktop)
            icon.width = icon.height = sz
            ui.uilib.desktop.children.insert(0, icon)
            ui.uilib.desktop.children.insert(0, techIcon)
            techIcon.top = 0
            techIcon.left = 0
            ui.uilib.Reload()
            renderJob.Update(ui)
            renderJob.RenderUI(ui)
            renderJob.ScheduleOnce()
            renderJob.WaitForFinish()
            baseTexture.SaveSurfaceToFile(name, trinity.TRIIFF_PNG)
            blue.pyos.synchro.Yield()
            if ((counter % 1000) == 0):
                msg = ('%s / %s' % (counter, len(toRender)))
                print '\n',
                print msg
                eve.Message('CustomNotify', {'notify': msg})

        msg = ('Done rendering out type icons in size %sx%s to folder %s.<br>Rendered %s types and skipped %s types' % (sz,
         sz,
         filePath,
         (len(toRender) - numSkipped),
         numSkipped))
        Msg(msg)



    def IconsRender(self):
        Msg('Rendering type icons...')
        self.TypesRender()
        Msg('Rendering categories...')
        self.IconsCategoriesRender()
        Msg('Rendering corp logos...')
        self.IconsCorporationRender()
        Msg('Rendering icon sheets...')
        self.IconsIconRender()
        Msg('All icons have been rendered. All done!')



    def NothingRender(self):
        return 



    def SetVars(self, renderVars):
        rv = util.KeyVal(username='', password='', routine='', parameter='')
        if (renderVars is not None):
            if (len(renderVars) >= 3):
                rv.username = renderVars[0]
                rv.password = renderVars[1]
                rv.routine = renderVars[2]
            if (len(renderVars) == 4):
                rv.parameter = renderVars[3]
        self.renderVars = rv



    def GetVars(self):
        return self.renderVars



    def GoSlimLogin(self):
        rv = self.renderVars
        if rv:
            func = getattr(self, ('%sRender' % rv.routine.capitalize()), None)
            if func:
                self.GoLogin(rv.username, rv.password)
                self.WaitForEvent('login')
                self.GoCharsel()
                self.WaitForEvent('station')
                self.GoRoutine(rv.routine, func)



    def GoLogin(self, username, password):
        sm.GetService('loading').GoBlack()
        s1 = sm.GetService('sceneManager').GetActiveScene1()
        if (s1 is not None):
            s1.display = 0
        s2 = sm.GetService('sceneManager').GetActiveScene2()
        if (s2 is not None):
            s2.display = 0
        eve.triapp.tridev.ui.display = 1
        sm.GetService('gameui').OpenExclusive('login')
        user = username
        pwd = util.PasswordString(password)
        sm.GetService('loading').ProgressWnd(mls.UI_LOGIN_LOGGINGIN, mls.UI_LOGIN_CONNECTINGCLUSTER, 1, 100)
        blue.pyos.synchro.Yield()
        eve.Message('OnConnecting')
        blue.pyos.synchro.Yield()
        eve.Message('OnConnecting2')
        blue.pyos.synchro.Yield()
        serverName = util.GetServerName()
        server = login.GetServerIP(serverName)
        loginparam = [user,
         pwd,
         server,
         26000,
         0]
        try:
            sm.GetService('connection').Login(loginparam)
        except:
            raise 
        sm.GetService('device').PrepareMain()
        blue.pyos.synchro.Yield()
        blue.pyos.synchro.Yield()
        blue.pyos.synchro.Yield()
        blue.pyos.synchro.Yield()



    def GoCharsel(self):
        chars = sm.GetService('cc').GetCharactersToSelect()
        characterid = None
        for char in chars:
            characterid = char.characterID
            break

        if characterid:
            sm.GetService('sessionMgr').PerformSessionChange('charsel', sm.RemoteSvc('charUnboundMgr').SelectCharacterID, characterid)



    def GoRoutine(self, routine, func):
        uthread.pool(('Webtools :: GoRoutine :: %sRender' % routine.capitalize()), func)



    def IconsIconRender(self):
        x = IconRoutines()
        x.TotalBatchRender(icons=1)



    def IconsCorporationRender(self):
        x = IconRoutines()
        x.TotalBatchRender(corporation=1)



    def IconsCategoriesRender(self):
        x = IconRoutines()
        x.TotalBatchRender(categories=1)



    def GenericQuit(self):
        sm.GetService('gameui').SaveSettings()
        blue.pyos.Quit('User requesting close')




class IconRoutines:
    __guid__ = 'webroutines.IconRoutines'
    __exportedcalls__ = {'RenderIconSheets': [],
     'RenderCategory': [],
     'RenderAlliances': [],
     'RenderCorporations': []}

    def __init__(self, ext = None):
        if (ext is None):
            ext = 'png'
        self.exportExtension = ext
        self.fileFormat = getattr(trinity, ('TRIIFF_%s' % self.exportExtension.upper()))



    def __CopyWithAlpha(self, srcSurface, dstSurface, srcSize, dstSize):
        srcSurface.LockBuffer()
        dstSurface.LockBuffer()
        tmpCol = trinity.TriColor()
        bpCol = trinity.TriColor()
        srcCol = trinity.TriColor()
        dstCol = trinity.TriColor()
        factor = (srcSize / dstSize)
        factor2 = (factor * factor)
        for x in xrange(dstSize):
            for y in xrange(dstSize):
                r = g = b = a = 0.0
                for xi in xrange(factor):
                    for yi in xrange(factor):
                        srcCol.FromInt(srcSurface.GetPixel(((factor * x) + xi), ((factor * y) + yi)))
                        r += srcCol.r
                        g += srcCol.g
                        b += srcCol.b
                        a += srcCol.a


                if a:
                    a /= factor2
                    r /= factor2
                    g /= factor2
                    b /= factor2
                    r *= a
                    g *= a
                    b *= a
                    dstCol.FromInt(dstSurface.GetPixel(x, y))
                    dstCol.Scale((1.0 - a))
                    dstCol.r = min(1.0, (r + dstCol.r))
                    dstCol.g = min(1.0, (g + dstCol.g))
                    dstCol.b = min(1.0, (b + dstCol.b))
                    dstCol.a = min(1.0, (a + dstCol.a))
                    dstSurface.SetPixel(x, y, dstCol.AsInt())


        srcSurface.FlushBuffer()
        dstSurface.FlushBuffer()



    def RenderIconSheets(self, f, t, doBackground = 1, bgcolor = (0.0, 0.0, 0.0), folderLabel = 'black', root = None, iconsize = 64):
        for textureNo in xrange(f, (t + 1)):
            factor = 1.0
            if ('items' in folderLabel):
                iconsize = uix.GetIconSize(textureNo)
            factors = []
            while (int((factor * iconsize)) >= 16):
                factors.append(factor)
                factor *= 0.5

            self._RenderIconSheet(textureNo, doBackground, bgcolor, folderLabel, iconsize, factors, root)




    def _RenderIconSheet(self, textureNum, doBackground = 0, bgcolor = (0.0, 0.0, 0.0), folderLabel = 'black', iconsize = 64, factors = [1.0], root = None):
        Msg(('Rendering Icon Sheet %s %s' % (folderLabel, textureNum)))
        if not root:
            root = 'res:/UI/Texture/Icons/icons'
        fullpath = ('%s%s%s.dds' % (root,
         ['', '0'][((int(textureNum) < 10) and (str(textureNum)[0] != '0'))],
         textureNum))
        dev = trinity.device
        iconSurface = dev.CreateOffscreenPlainSurface(256, 256, trinity.TRIFMT_A8R8G8B8, trinity.TRIPOOL_SYSTEMMEM)
        try:
            iconSurface.LoadSurfaceFromFile(util.ResFile(fullpath))
        except:
            log.LogWarn(('The system cannot find the file specified: %s' % fullpath))
            sys.exc_clear()
        col = trinity.TriColor()
        col.SetRGB(bgcolor[0], bgcolor[1], bgcolor[2])
        dr = DirectoryRoutines()
        for factor in factors:
            size = int((iconsize * factor))
            filePath = (blue.win32.SHGetFolderPath(blue.win32.CSIDL_PERSONAL) + ('/EVE/capture/Screenshots/%s/%s_%s/' % (folderLabel,
             size,
             size)))
            dr.GenericCheckCreateDirectory(filePath)
            sur = dev.CreateRenderTarget((size * (256 / iconsize)), (size * (256 / iconsize)), trinity.TRIFMT_A8R8G8B8, 0, 0, 1)
            surrect = trinity.TriRect(0, 0, (size * (256 / iconsize)), (size * (256 / iconsize)))
            dev.ColorFill(sur, surrect, col)
            sur.FlushBuffer()
            self._IconRoutines__CopyWithAlpha(iconSurface, sur, 256, (size * (256 / iconsize)))
            savesur = dev.CreateOffscreenPlainSurface((size * (256 / iconsize)), (size * (256 / iconsize)), trinity.TRIFMT_A8R8G8B8, trinity.TRIPOOL_SYSTEMMEM)
            sur.CopySurfaceTo(savesur)
            counter = 1
            left = 0
            top = 0
            for i in xrange(((256 / int(iconsize)) ** 2)):
                i += 1
                rr = trinity.TriRect(left, top, (left + size), (top + size))
                savesur.SaveSurfaceToFile((filePath + ('icon%s%s_%s%s.%s' % (['', '0'][(int(textureNum) < 10)],
                 textureNum,
                 ['', '0'][(int(i) < 10)],
                 i,
                 self.exportExtension))), self.fileFormat, rr)
                counter += 1
                left += size
                if (left >= int((256 * factor))):
                    left = 0
                    top += size





    def BatchRender(self, toRender, folder, save = 1, iconsize = 64):
        (categoryid, groupid,) = toRender
        manyTypes = []
        if categoryid:
            manyTypes = [ each for each in cfg.invtypes if (each.Group().Category().id == categoryid) ]
        elif groupid:
            manyTypes = [ each for each in cfg.invtypes if (each.Group().id == groupid) ]
        lr = LoggingRoutines()
        lr.CreateLogFile(('batchrender_types_%s_%s' % (iconsize, len(manyTypes))))
        lr.WriteLogFile(('%s types in %sx%s to render: ' % (len(manyTypes),
         iconsize,
         iconsize)))
        notRender = []
        for invtype in manyTypes:
            lr.WriteLogFile((' - rendering typeID %s: %s' % (invtype.typeID, invtype.typeName)))
            print ('BatchRender %s' % invtype.typeName)
            try:
                self.RenderType(invtype.typeID, folder, save, iconsize)
            except:
                lr.WriteLogFile(('Failed to render typeID %s: %s' % (invtype.typeID, invtype.typeName)))
                sys.exc_clear()
            blue.pyos.BeNice(150)

        for each in notRender:
            lr.WriteLogFile(each)

        lr.CloseLogFile()



    def RenderType(self, typeID, folder = 'testing', save = 1, iconsize = 64, recursive = 0):
        folder = folder.replace(' ', '')
        dev = trinity.device
        triapp = eve.rot.GetInstance('app:/App', 'triui.App')
        root = (blue.win32.SHGetFolderPath(blue.win32.CSIDL_PERSONAL) + '/EVE/capture/Screenshots')
        filePath = (blue.win32.SHGetFolderPath(blue.win32.CSIDL_PERSONAL) + '/EVE/capture/Screenshots/Renders/')
        dr = DirectoryRoutines()
        dr.GenericCheckCreateDirectory(filePath)
        typeinfo = cfg.invtypes.Get(typeID)
        group = typeinfo.Group()
        categoryID = group.categoryID
        if not typeinfo.GraphicFile():
            return 
        fullpath = ''
        path_current = ('cache:/Pictures/Gids/' + sm.GetService('photo').GetPictureFileName(typeinfo, iconsize))
        fullpath_current = sm.GetService('photo').CheckAvail(path_current)
        if fullpath_current:
            fullpath = path_current
        file = blue.ResFile()
        if not file.Open(fullpath):
            if (categoryID == const.categoryPlanetaryInteraction):
                if (group.id not in (const.groupPlanetaryLinks, const.groupPlanetaryCustomsOffices)):
                    sm.GetService('photo').GetPinPhoto(typeID, typeinfo=typeinfo, size=iconsize)
                elif (group.id == const.groupPlanetaryCustomsOffices):
                    sm.GetService('photo').GetPhoto(typeID, typeinfo, size=iconsize)
                else:
                    return 
            else:
                sm.GetService('photo').GetPhoto(typeID, typeinfo, size=iconsize)
            if not recursive:
                del file
                self.RenderType(typeID, folder=folder.split('_')[0], save=save, iconsize=iconsize, recursive=1)
                return 
        if file:
            del file
        sur = dev.CreateOffscreenPlainSurface(iconsize, iconsize, trinity.TRIFMT_A8R8G8B8, trinity.TRIPOOL_SYSTEMMEM)
        blue.pyos.synchro.Sleep(100)
        try:
            sur.LoadSurfaceFromFile(util.ResFile(fullpath))
        except:
            print ('failed Rendering typeID: %s, size: %s %s' % (typeID,
             iconsize,
             fullpath))
        sur.SaveSurfaceToFile((filePath + ('%s.%s' % (typeID, self.exportExtension))), self.fileFormat)



    def RenderCategory(self, category, save = 1):
        self.BatchRender((category, None), ('%s' % cfg.invcategories.Get(category).categoryName.lower()), save, 512)



    def RenderTech3Ships(self, move = True):
        Msg('Rendering T3 ships')
        tech3IconToTypeID = {'icon90_01': '29986',
         'icon91_01': '29984',
         'icon92_01': '29988',
         'icon93_01': '29990'}
        self.RenderIconSheets(90, 93, 1, folderLabel='tech3', iconsize=256)
        if move:
            outputRoot = ('%s%s' % (blue.win32.SHGetFolderPath(blue.win32.CSIDL_PERSONAL), '/EVE/capture/Screenshots/'))
            output = ('%s/EVE/capture/Screenshots/tech3' % blue.win32.SHGetFolderPath(blue.win32.CSIDL_PERSONAL))
            for (root, folders, files,) in os.walk(output):
                iconSize = root.split(os.sep)[-1]
                if (iconSize != '256_256'):
                    continue
                for iconFile in files:
                    (filename, ext,) = iconFile.split('.')
                    outputFile = ('%s/Renders/%s.png' % (outputRoot, tech3IconToTypeID[filename]))
                    path = ('%s/%s' % (root, iconFile))
                    shutil.move(path, outputFile)


            shutil.rmtree(output)



    def RenderCorporations(self):
        root = 'res:/UI/Texture/Corps/corps'
        (lo, hi,) = self.GetLoHi(root)
        self.RenderIconSheets(lo, hi, 0, (0.0, 0.0, 0.0), 'Icons\\corporations', root=root, iconsize=128)



    def TotalBatchRender(self, icons = None, categories = None, corporation = None):
        dr = DirectoryRoutines()
        dr.DeleteCachedFile(None, 'Gids', 1)
        if icons:
            root = 'res:/UI/Texture/Icons/icons'
            (lo, hi,) = self.GetLoHi(root)
            self.RenderIconSheets(lo, hi, 0, (0.0, 0.0, 0.0), 'Icons\\items')
        if corporation:
            self.RenderCorporations()
        if categories:
            renderCategories = [const.categoryDrone,
             const.categoryShip,
             const.categoryStation,
             const.categoryStructure,
             const.categoryDeployable,
             const.categorySovereigntyStructure,
             const.categoryPlanetaryInteraction]
            for categoryID in renderCategories:
                Msg(('Rendering category %s' % categoryID))
                self.RenderCategory(categoryID)

            self.RenderTech3Ships()



    def GetLoHi(self, resPath):
        f = blue.ResFile()
        retVal = {'lo': 1,
         'hi': 1}
        for x in xrange(1, MAX_ICON_RANGE):
            check = f.FileExists(('%s%s.dds' % (resPath, (x if (x >= 10) else ('0%s' % x)))))
            if check:
                if (x > retVal['hi']):
                    retVal['hi'] = x
                if (x < retVal['lo']):
                    retVal['lo'] = x

        f.Close()
        return retVal.itervalues()




class LoggingRoutines:
    __guid__ = 'webroutines.LoggingRoutines'
    __exportedcalls__ = {'CreateLogFile': [],
     'WriteToLogfile': []}

    def __init__(self):
        self.logfile = None



    def CreateLogFile(self, ex = ''):
        logfilepath = (blue.win32.SHGetFolderPath(blue.win32.CSIDL_PERSONAL) + '/EVE/logs/RenderLogs/')
        logfilename = ('%s_%s_renderlog.txt' % (strftime('%Y.%m.%d-%H.%M', gmtime()), ex))
        dr = DirectoryRoutines()
        dr.GenericCheckCreateDirectory(logfilepath)
        filename = (logfilepath + logfilename)
        self.logfile = blue.os.CreateInstance('blue.ResFile')
        if not self.logfile.Open(filename, 0):
            self.logfile.Create(filename)
        self.WriteLogFile('#')
        self.WriteLogFile(('# Started at ' + strftime('%Y.%m.%d-%H.%M', gmtime())))
        self.WriteLogFile('#')



    def WriteLogFile(self, line):
        if self.logfile:
            self.logfile.Write((line.encode('utf8') + '\n'))



    def CloseLogFile(self):
        if self.logfile:
            self.WriteLogFile('#')
            self.WriteLogFile(('# Ended at ' + strftime('%Y.%m.%d-%H.%M', gmtime())))
            self.WriteLogFile('#')
            self.logfile.Close()




class DirectoryRoutines:
    __guid__ = 'webroutines.DirectoryRoutines'

    def __init__(self):
        self.createdDirectories = {}



    def DeleteCachedFile(self, itemID, folder = 'Portraits', flush = 0):
        resPath = (blue.os.cachepath + ('Pictures/%s/' % folder))
        for (rRoot, dirs, files,) in os.walk(resPath):
            for rFile in files:
                rFile = str(rFile)
                if (flush or rFile.startswith(str(itemID))):
                    try:
                        os.remove((str(rRoot) + str(rFile)))
                    except:
                        sys.exc_clear()





    def GenericCheckCreateDirectory(self, name, dry_run = 0):
        if DEBUGMODE:
            self.createdDirectories = {}
        name = os.path.normpath(name)
        created_dirs = []
        if (os.path.isdir(name) or (name == '')):
            return created_dirs
        else:
            if self.createdDirectories.get(os.path.abspath(name)):
                return created_dirs
            (head, tail,) = os.path.split(name)
            tails = [tail]
            while (head and (tail and (not os.path.isdir(head)))):
                (head, tail,) = os.path.split(head)
                tails.insert(0, tail)

            for d in tails:
                head = os.path.join(head, d)
                abs_head = os.path.abspath(head)
                if self.createdDirectories.get(abs_head):
                    continue
                if not dry_run:
                    try:
                        os.mkdir(head)
                        created_dirs.append(head)
                    except OSError, exc:
                        raise ("could not create '%s': %s" % (head, exc[-1]))
                self.createdDirectories[abs_head] = 1

            return created_dirs



exports = {'webroutines.DirectoryRoutines': DirectoryRoutines,
 'webroutines.IconRoutines': IconRoutines,
 'webroutines.LoggingRoutines': LoggingRoutines}

